package com.rongji.dfish.demo.editor.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.google.gson.Gson;
import com.rongji.dfish.base.Utils;
import com.rongji.dfish.base.util.DateUtil;
import com.rongji.dfish.demo.constant.DemoConstants;
import com.rongji.dfish.demo.editor.service.CommonService;
import com.rongji.dfish.demo.editor.service.EditorDirService;
import com.rongji.dfish.demo.editor.service.EditorService;
import com.rongji.dfish.demo.editor.service.uiadaptor.AdaptorManager;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentData;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentInfo;
import com.rongji.dfish.demo.editor.service.uiadaptor.ComponentRelation;
import com.rongji.dfish.demo.editor.service.uiadaptor.PropertyDefine;
import com.rongji.dfish.demo.editor.service.uiadaptor.TypeAdaptor;
import com.rongji.dfish.demo.editor.view.EditorView;
import com.rongji.dfish.demo.entity.DfishView;
import com.rongji.dfish.demo.entity.DfishViewDir;
import com.rongji.dfish.demo.entity.DfishViewNode;
import com.rongji.dfish.demo.pub.view.PubView;
import com.rongji.dfish.framework.FrameworkHelper;
import com.rongji.dfish.framework.controller.BaseController;
import com.rongji.dfish.framework.plugin.file.service.FileService;
import com.rongji.dfish.ui.Combo;
import com.rongji.dfish.ui.command.CommandGroup;
import com.rongji.dfish.ui.command.DialogCommand;
import com.rongji.dfish.ui.command.JSCommand;
import com.rongji.dfish.ui.command.MenuCommand;
import com.rongji.dfish.ui.command.ReplaceCommand;
import com.rongji.dfish.ui.helper.GridPanel;
import com.rongji.dfish.ui.json.J;
import com.rongji.dfish.ui.layout.VerticalLayout;
import com.rongji.dfish.ui.layout.View;
import com.rongji.dfish.ui.layout.grid.GridColumn;
import com.rongji.dfish.ui.layout.grid.Tr;
import com.rongji.dfish.ui.widget.Leaf;
import com.rongji.dfish.ui.widget.PageBar;

@Controller
@RequestMapping("/editor")
/**
 * 视图编辑控制器
 * 
 * @author DFish Team
 *
 */
public class EditorController extends BaseController {
	@Autowired
	private EditorService editorService;
	@Autowired
	private EditorDirService editorDirService;
	@Autowired
	private FileService fileService;
	
	public EditorService getEditorService() {
		return editorService;
	}
	
	public void setEditorService(EditorService editorService) {
		this.editorService = editorService;
	}
	
	public EditorDirService getEditorDirService() {
		return editorDirService;
	}
	
	public void setEditorDirService(EditorDirService editorDirService) {
		this.editorDirService = editorDirService;
	}
	
	public FileService getFileService() {
		return fileService;
	}

	public void setFileService(FileService fileService) {
		this.fileService = fileService;
	}

	@RequestMapping("/{viewId}")
	@ResponseBody
	public Object index(HttpServletRequest request) throws Exception {
		String viewId = request.getParameter("viewId");
		// FIXME 目前调用的是reload,index方法似乎没有用到
		String fromModule = request.getParameter("fromModule");
		View view = getIndexView(viewId,fromModule);
		return view;
	}
	
	@RequestMapping("/eventOptions")
	@ResponseBody
	public Object eventOptions(HttpServletRequest request) throws Exception {
		String key=Utils.getParameter(request, "key");
		if(key==null){
			key="";
		}
		int PAGE_SIZE=6;
		View view=new View();
		VerticalLayout vl=new VerticalLayout("root");
		view.setNode(vl);
		vl.setCls("bd-mod bg-white").setHmin(2).setWmin(2).setHeight("212").setWidth("500");
		GridPanel gp=new GridPanel("grid");
		gp.setFace(GridPanel.FACE_LINE).setLimit(PAGE_SIZE).setNobr(true).setHasTableHead(false).setCombo(new Combo().setField(new Combo.Field("E", "E")));
		gp.setPub(new Tr().setOn(Tr.EVENT_CLICK,"$.dialog(this).commander.complete(this)").setHeight("30"));
		gp.setFocusable(true);
		
		gp.addColumn(GridColumn.hidden(0, "E"));
		gp.addColumn(GridColumn.text(1, "N",null,"*").setFormat("<table width='100%' cellspacing='0' cellpadding='0'><tr><td class='f-nobr'>$E</td><td align='right' class='f-nobr' style='overflow:hidden;color:green;'>&nbsp;$N</td></tr></table>"));
		List<Object[]> raw=AdaptorManager.getInstance().getCompInfo().getOptions(ComponentInfo.ELEM_TYPE_EVENT);
		List<Object[]>result=new ArrayList<Object[]>();
		for(Object[] r:raw){
			String eventKey=(String) r[0];
			if(eventKey.contains(key)){
				result.add(r);
			}
		}

		gp.setGridData(result);
		vl.add(gp);
		
		PageBar page =new PageBar("page",PageBar.TYPE_MINI);
		page.setTarget("grid").setAlign(PageBar.ALIGN_RIGHT);
		page.setBtncount(5);
		vl.add(page,"30");
		
		
		return view;
		// FIXME 目前调用的是reload,index方法似乎没有用到
//		View view = getIndexView(getRequest(), viewId);
//		return view;
	}
	
	private View getIndexView(String viewId,String fromModule) throws Exception {
		DfishView targetView = editorService.getView(viewId);
		List<DfishViewNode> viewNodes = editorService.findViewNodes(viewId);
		AdaptorManager.getInstance().getCompInfo().sortViewNodesByGroups(viewNodes);
		
		List<DfishView> versions = editorService.findVersionViews(targetView.getViewOrigin(), EditorService.STATUS_VERSION);
		
		DfishViewDir targetDir = editorDirService.get(targetView.getViewDir());
		//FIXME fromModule 如果是示例的话，应该是只读模式
		View view = EditorView.buildIndexView(targetView, targetDir, viewNodes, versions, fromModule);
		return view;
	}
	
	private boolean isNoPermssion(HttpServletRequest request, DfishView currView) {
		boolean noPermission = EditorService.STATUS_VERSION.equals(currView.getViewStatus());
		if (!noPermission && "1".equals(currView.getCategory())) {
			String loginUser = FrameworkHelper.getLoginUser(request);
			noPermission = Utils.isEmpty(loginUser);
		}
		return noPermission;
	}
	
	@RequestMapping("/reload")
	@ResponseBody
	public Object reload(HttpServletRequest request) throws Exception {
		String viewId = request.getParameter("viewId");
		String fromModule = request.getParameter("fromModule");
		View view = getIndexView(viewId,fromModule);
		return new ReplaceCommand(view.findNodeById(PubView.MAIN_ROOT));
	}
	
	
	//FIXME 缺少一个OPEN。当组件有变化的时候，必须根据这个act来做更新动作
	@RequestMapping("/open/{nodeId}")
	@ResponseBody
	public Object open(@PathVariable String nodeId) {
//		List<DfishViewNode> subs=null;
		String viewId=null; 
		if(nodeId.startsWith("ROOT")){
			viewId=nodeId.substring(4);
			nodeId=DemoConstants.ID_ROOT;
//			subs=editorService.findTopNodes(viewId);
		}else{
			DfishViewNode node=editorService.getViewNode(nodeId);
			viewId=node.getViewId();
//			subs=editorService.findSubNodes(nodeId);
		}
		List<DfishViewNode> allNodes= editorService.findViewNodes(viewId);
		Leaf shell=new Leaf();
		HashSet<String> allParent=new HashSet<String>();
		for(DfishViewNode sub:allNodes){
			allParent.add(sub.getNodeParent());
		}
		for(DfishViewNode sub:allNodes){
			if(!sub.getNodeParent().equals(nodeId)){
				continue;
			}
			Leaf t=new Leaf().setId(sub.getNodeId());
			shell.add(t);
			if(Utils.notEmpty(sub.getNodeName())){
				t.setText(sub.getNodeType()+"("+sub.getNodeName()+")");
			}else{
				t.setText(sub.getNodeType());
			}
			if(allParent.contains(sub.getNodeId())){
				shell.setSrc("editor/open/"+sub.getNodeId());
			}
		}
		return shell;//FIXME 应该支持到return view
	}
	@RequestMapping("/nodeMenu")
	@ResponseBody
	public Object nodeMenu(HttpServletRequest request) {
		String viewId = request.getParameter("viewId");
		String nodeId = request.getParameter("nodeId");
		DfishViewNode viewNode = null;
		if(Utils.notEmpty(nodeId) && !DemoConstants.ID_ROOT.equals(nodeId)){
			viewNode = editorService.getViewNode(nodeId);
		} else {
			viewNode = EditorView.getRootViewNode(viewId);
		}
		DfishView currView = editorService.getView(viewId);
		boolean noPermission = isNoPermssion(request, currView);
		List<DfishViewNode> subs=editorService.findSubNodes(nodeId,viewId);
		HashSet<String> subTypes=new HashSet<String>();
		HashSet<String> subIds=new HashSet<String>();
		for(DfishViewNode sub:subs){
			subTypes.add(sub.getNodeType());
			ComponentData cd=AdaptorManager.parseData(sub);
			if(cd!=null&&cd.getProps()!=null){
				subIds.add(cd.getProps().get("id"));
			}
		}
		String fromModule = request.getParameter("fromModule");
		MenuCommand menu = EditorView.buildNodeMenu(viewNode, noPermission,subTypes,subIds,fromModule);
		return menu;
	}
	@RequestMapping("/editNode")
	@ResponseBody
	public Object editNode(HttpServletRequest request) {
//		Locale.setDefault(Locale.SIMPLIFIED_CHINESE);
		//FIXME 如果 nodeId为以下格式  NEW_Html_0001 表示这个是0001这个节点下的子节点，类型为 Html
		//包括ORDER viewId都要自动产生。
		String nodeId = request.getParameter("nodeId");
		String nodeType = request.getParameter("nodeType");
		String nodeMode = request.getParameter("nodeMode");
		String nodeParent = request.getParameter("nodeParent");
		String viewId = request.getParameter("viewId");
		DfishViewNode viewNode=null;
		if(Utils.isEmpty(nodeId) || "NEW".equals(nodeId)){
			viewNode =new DfishViewNode();
			viewNode.setNodeContent("{\"type\":\""+nodeType+"\"" +
					(Utils.isEmpty(nodeMode)?"":(",\"mode\":\""+nodeMode+"\"" ))+
					"}");
			viewNode.setNodeId(nodeId);
			viewNode.setNodeOrder(editorService.getNewOrder(nodeParent));
			viewNode.setNodeType(nodeType);
			viewNode.setNodeParent(nodeParent);
			viewNode.setViewId(viewId);
		}else{
			viewNode=editorService.getViewNode(nodeId);
			viewId=viewNode.getViewId();
		}
		DfishViewNode pNode = null;
		if (DemoConstants.ID_ROOT.equals(nodeParent)) {
			pNode = new DfishViewNode();
			pNode.setNodeId(DemoConstants.ID_ROOT);
			pNode.setViewId(viewId);
		} else {
			// FIXME 根节点编辑时报错(理论上不该被编辑)
			pNode = editorService.getViewNode(viewNode.getNodeParent());
		}
		DfishView dview=editorService.getView(viewId);
		String fromModule = request.getParameter("fromModule");
		boolean readonly=isNoPermssion(request, dview) || !DemoConstants.MOD_EXPERIENCE.equals(fromModule);
		View view = EditorView.buildPropView(viewNode, pNode,readonly);
		DialogCommand comps=new DialogCommand("comps", "std", "编辑组件信息",  
			DialogCommand.WIDTH_MEDIUM, DialogCommand.HEIGHT_LARGE,
			DialogCommand.POSITION_MIDDLE,null);
		comps.setNode(view);
		return comps;//FIXME 应该支持到return view
	}

	@RequestMapping(value="/saveNode")
	@ResponseBody
	public Object saveNode(HttpServletRequest request,HttpServletResponse response) {
		String nodeId=request.getParameter("nodeId");
		
		String nodeType=request.getParameter("nodeType");
		String nodeParent=request.getParameter("nodeParent");
		String parentType=request.getParameter("parentType");
		String mode=request.getParameter("nodeMode");
		DfishViewNode viewNode=null;
		boolean isNew=Utils.isEmpty(nodeId) || "NEW".equals(nodeId);
		if(isNew){
			DfishViewNode parentViewNode=null;
			viewNode =new DfishViewNode();
			if(DemoConstants.ID_ROOT.equals(nodeParent)){
				viewNode.setNodeParent(DemoConstants.ID_ROOT);
				String viewId = request.getParameter("viewId");
				viewNode.setViewId(viewId);
			}else{
				parentViewNode = editorService.getViewNode(nodeParent);
				viewNode.setNodeParent(nodeParent);
				viewNode.setViewId(parentViewNode.getViewId());
			}
			viewNode.setNodeId(CommonService.getNewId());
			viewNode.setNodeType(nodeType);
			
		}else{
			viewNode = editorService.getViewNode(nodeId);
		}
		
		viewNode.setNodeOrder(Long.parseLong(request.getParameter("nodeOrder")));

//		String id=request.getParameter("id");
//		if(Utils.notEmpty(id)){
//			viewNode.setNodeName(id);
//		}else{
//			String name=request.getParameter("name");
//			if (Utils.notEmpty(name)) {
//				viewNode.setNodeName("*" + name);
//			}
//		}
		
		String currType = viewNode.getNodeType();
		TypeAdaptor adaptor = AdaptorManager.getInstance().getAdaptor(currType);
		ComponentData data=new ComponentData();
		data.setType(nodeType);
		data.setMode(mode);
		Gson gson=new Gson();

		for(PropertyDefine prop: adaptor.getDefineProps()){
			String v=request.getParameter(prop.getName());
			//FIXME DialogTemplate和DialogCommand 编辑页面中宽度和高度可以自己写，
			//需要判断radio的值，若为""，则取spinner的值,之后需要把有这种需求的组件整合
			if("height".equals(prop.getName())||"width".equals(prop.getName())){
				if("".equals(v)){
					v=request.getParameter("target"+prop.getName());
				}
			}	
			if(Utils.notEmpty(v)){
				if(data.getProps()==null){
					data.setProps(new TreeMap<String,String>());
				}
				data.getProps().put(prop.getName(), v);
			}
		}
		
		//处理 添加到父节点需要的追加属性
		List<PropertyDefine> appendingProps=AdaptorManager.getInstance().getCompRelation().getAppendingProperies(parentType, viewNode.getNodeType(), mode);
		if ( Utils.notEmpty(appendingProps)) {
			for (PropertyDefine propDef : appendingProps) {
				String value=request.getParameter(propDef.getName());
				if(Utils.notEmpty(value)){
					if(data.getParentProps()==null){
						data.setParentProps(new LinkedHashMap<String,String>());
					}
					data.getParentProps().put(propDef.getName(), value);
				}
			}
		}
		if (AdaptorManager.getInstance().getCompInfo().hasDataProp(adaptor.getTypeName())) {
			data.setDataProps(getExtPropMap(request,"D"));
			Map<String,String> option = new HashMap<String,String>();
			option = getExtPropMap(request,"P");
			if(option!=null){
				String valueOp = "[";
				for(Entry<String, String> entry : option.entrySet()) {
						valueOp += "[\""+entry.getKey()+"\",\""+entry.getValue()+"\"],";
				}
				valueOp = valueOp.substring(0, valueOp.length()-1)+ "]";
				data.getProps().put("options",valueOp);
			}
		}
		if (AdaptorManager.getInstance().getCompInfo().hasEventProp(adaptor.getTypeName())) {
			data.setEventProps(getExtPropMap(request,"E"));
		}
		if (AdaptorManager.getInstance().getCompInfo().hasHiddensProp(adaptor.getTypeName())) {
			data.setHiddensProps(getExtPropMap(request,"H"));
		}
//			boolean hasValue = true;
//			int i=0;//FIXME 如果 I=3被删掉导致i=4和i=5丢失。
//			do {
//				String key = request.getParameter("DK_" + i);
//				String value = request.getParameter("DV" + i);
//				hasValue = Utils.notEmpty(value);
//				if (!hasValue) {
//					break;
//				}
//				data.getDataProps().put(key, value);
//				i++;
//			} while (hasValue);
		
		viewNode.setNodeContent(gson.toJson(data));//FIXME
		viewNode.setNodeName(EditorService.getNodeName(data));
		

		if(isNew){
			editorService.save(viewNode);
		}else{
			editorService.update(viewNode);
		}
		JSCommand js = new JSCommand("var d=$.dialog(this);editor.file.reloadEditor(d.ownerView,'" + viewNode.getViewId() + "');d.close();");
		return js;
		//FIXME 应该支持到return command
	}
	
	private Map<String, String> getExtPropMap(HttpServletRequest request, String perfix) {
		LinkedHashMap<String,String >map=new LinkedHashMap<String,String>();
		java.util.Enumeration<String > names=request.getParameterNames();
		List<Integer> keys=new ArrayList<Integer>();
		while(names.hasMoreElements()){
			String name=names.nextElement();
			if(name.startsWith(perfix+"K_")){
				keys.add(Integer.parseInt(name.substring(3)));
			}
		}
		Collections.sort(keys);
		for(Integer i:keys){
			String key=Utils.getParameter(request, perfix+"K_"+i);
			String value=Utils.getParameter(request, perfix+"V_"+i);
			map.put(key, value);
		}
		if(map.size()==0){
			return null;
		}
		return map;
	}

	private DfishViewNode newViewNode(String nodeType, String name, DfishViewNode parentNode) {
		DfishViewNode gridRowsNode = new DfishViewNode();
		gridRowsNode.setNodeId(CommonService.getNewId());
		gridRowsNode.setNodeName("*" + name);
		gridRowsNode.setNodeType(nodeType);
		gridRowsNode.setNodeContent("{\"type\":\"" + nodeType + "\",\"props\":{\"name\":\"" + name + "\"}}");
		String nodeParent = parentNode.getNodeId();
		Long nodeOrder = editorService.getNewOrder(nodeParent);
		gridRowsNode.setNodeOrder(nodeOrder);
		gridRowsNode.setNodeParent(nodeParent);
		gridRowsNode.setViewId(parentNode.getViewId());
		return gridRowsNode;
	}
	
	@RequestMapping(value="/deleteNode/{nodeId}")
	@ResponseBody
	public Object deleteNode(@PathVariable String nodeId) {
		DfishViewNode deleteRoot = editorService.deleteNodesCascade(nodeId);
		String viewId = deleteRoot.getViewId();
//		return new JSCommand(
//				"VM(this).find('compTree').treeDelete('"+nodeId+"');");
		return new JSCommand("editor.file.reloadEditor(this,'" + viewId + "');");	
	}
	@RequestMapping(value="/moveNode")
	@ResponseBody
	public Object moveNode(HttpServletRequest request,HttpServletResponse response) throws Exception {
		//两种移动 一种是上下移动
		//一种是移动到其他文件夹
		String nodeId=request.getParameter("nodeId");
		String moveType=request.getParameter("moveType");
		String viewId = request.getParameter("viewId");
		String pNode=request.getParameter("pNode");
		//如果pNode不为空，并且不为nodeId对应的pNode 则是移动到其他节点。否则仅仅调整顺序。
		DfishViewNode node = editorService.getViewNode(nodeId);
		if(pNode ==null||pNode.equals(node.getNodeParent())){
			String tips = editorService.sortNode(nodeId,moveType);
			if(tips.equals("")){
				return new JSCommand("editor.file.reloadEditor(this,'" + viewId + "');"
							+"VM(this).find('"+nodeId+"').reload();");
			} else {
				return new JSCommand("$.alert('"+tips+"');");
			}
		}else{
			editorService.moveNode(nodeId,pNode);
			return new JSCommand("var d=$.dialog(this);" 
							+"editor.file.reloadEditor(d.ownerView ,'" + viewId + "');"
							+"d.ownerView.find('"+pNode+"').reload();" 
							+"d.ownerView.find('"+nodeId+"').reload();d.close();");	
		}
		//FIXME 刷新父节点,如果pNode不为空，那么还要刷新新的父节点
	}
	
	@RequestMapping(value="/moveTargetSel")
	@ResponseBody
	public Object moveTargetSel(HttpServletRequest request,HttpServletResponse response) throws Exception {
		//两种移动 一种是上下移动
		//一种是移动到其他文件夹
		String nodeId=request.getParameter("nodeId");
		String viewId = request.getParameter("viewId");
//		String pNode=request.getParameter("pNode");
		//如果pNode不为空，并且不为nodeId对应的pNode 则是移动到其他节点。否则仅仅调整顺序。
//		DfishViewNode node = editorService.getViewNode(nodeId);
//		if(pNode ==null||pNode.equals(node.getNodeParent())){
//			editorService.sortNode(nodeId,moveType);
//		}else{
//			editorService.moveNode(nodeId,pNode);
//		}
		DialogCommand dc=PubView.getDialogCommand("moveTargetSel_win", "std", "选择移动到的节点", PubView.DIALOG_SIZE_MEDIUM, null);
//		DfishViewNode node =editorService.getViewNode(nodeId);
//		List<DfishViewNode> nodeList=editorService.findViewNodes(node.getViewId());
		
		List<DfishViewNode> nodeList=editorService.findViewNodes(viewId);
		AdaptorManager.getInstance().getCompInfo().sortViewNodesByGroups(nodeList);
		View view=EditorView.buildSelTargetView(nodeId,nodeList,viewId);
		dc.setNode(view);
		return dc;	
	}
	
	@RequestMapping(value="/copyNode")
	@ResponseBody
	public Object copyNode(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String nodeId = request.getParameter("nodeId");
		String copyType = request.getParameter("copyType");
		HttpSession session = request.getSession();
		session.setAttribute("nodeId", nodeId);
		session.setAttribute("copyType", copyType);
		String alertMsg = "粘贴板已更新";
		return PubView.getAlertInfo(alertMsg);
	}
	
	private boolean accept(DfishViewNode parent, DfishViewNode sub){
		//判断两届点是否有容纳关系
		ComponentRelation comRel=AdaptorManager.getInstance().getCompRelation();
		//判断一般容纳关系
		List<ComponentRelation.Information> acceptTypes=comRel.getAcceptType(parent.getNodeType());
		if(acceptTypes!=null){
			for(ComponentRelation.Information acceptType:acceptTypes){
				if(sub.getNodeType().equals(acceptType.getSubType())){
					return false;
				}
			}
		}
		
		//判断特殊容纳关系中是否有
		Map<String,List<ComponentRelation.Information>> specialPart=comRel.getSpecialParts(parent.getNodeType());
		if(Utils.notEmpty(specialPart)){
			for(Map.Entry<String,List<ComponentRelation.Information>> entry:specialPart.entrySet()){
				for(ComponentRelation.Information acceptType:entry.getValue()){
					if(sub.getNodeType().equals(acceptType.getSubType())){
						return false;
					}
				}
			}
		}
		
		//判断其他中是否有
		Map<String,List<ComponentRelation.Information>> otherPart=comRel.getOtherType(parent.getNodeType());
		if(Utils.notEmpty(otherPart)){
			for(Map.Entry<String,List<ComponentRelation.Information>> entry:otherPart.entrySet()){
				for(ComponentRelation.Information acceptType:entry.getValue()){
					if(sub.getNodeType().equals(acceptType.getSubType())){
						return false;
					}
				}
			}
		}
		return true;
	}
	
	private boolean singleLimit(DfishViewNode parent,DfishViewNode sub){
		ComponentRelation comRel=AdaptorManager.getInstance().getCompRelation();
		if(comRel.acceptSingle(parent.getNodeType(), sub.getNodeType())){
			List<DfishViewNode> subNodes = new ArrayList<DfishViewNode>();
			subNodes = editorService.findAllSubNodes(parent.getNodeId(),parent.getViewId());
			for(DfishViewNode node:subNodes){
				if(sub.getNodeType().equals(node.getNodeType())){
					return true;
				}
			}
		}
		return false;
	}
	

	@RequestMapping(value="/pasteNode")
	@ResponseBody
	public Object pasteNode(HttpServletRequest request,HttpServletResponse response) throws Exception{
		
		HttpSession session = request.getSession();
		String subNodeId = (String) session.getAttribute("nodeId");
		//没有复制任何节点
		if(subNodeId == null){
			return PubView.getAlertWarn("请先进行复制/剪切");
		}
		String targetNodeId = request.getParameter("targetNode");
		
		DfishViewNode targetNode = editorService.getDfishViewNode(targetNodeId);
		DfishViewNode subNode = editorService.getDfishViewNode(subNodeId);
		
		//判断两届点是否有容纳关系
		boolean containLimited = accept(targetNode,subNode);
		if(containLimited){
			return PubView.getAlertWarn("容纳关系不符，无法复制");
		} else {
			//判断唯一性限制
			boolean singleLimited=singleLimit(targetNode,subNode);
			if(singleLimited){
				return PubView.getAlertWarn("唯一性限制，无法复制");
			} else {
				//可以复制
				if(editorService.doPaste(targetNode,subNode)){
					return new JSCommand("editor.file.reloadEditor(this,'" + targetNode.getViewId() + "');"
						+"VM(this).find('"+targetNode.getNodeId()+"').reload();");
				} else{
					return PubView.getAlertWarn("粘贴板为空");
				}
			}
		}
	
	}
	
	@RequestMapping(value="/rebuildView/{viewId}")
	@ResponseBody
	public Object rebuildView(@PathVariable String viewId) throws Exception {
		String editContent = Utils.getParameter(getRequest(), "editContent");
		String json = editContent.replace("\r", "").replace("\n", "").replace("\t", "");
		// FIXME 多根节点情况处理
		ComponentData data = new Gson().fromJson(json, ComponentData.class);
		editorService.rebuild(viewId, data);
		return new JSCommand("editor.file.reloadEditor(this,'" + viewId + "');");
	}
	
	@RequestMapping(value="/exportView")
	public ModelAndView exportView(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		response.setContentType("text/html;charset=utf-8");  
        OutputStream output = null;
        try {
        	String viewId = request.getParameter("viewId");
        	DfishView dView = editorService.getView(viewId);
        	List<DfishViewNode> viewNodes = editorService.findViewNodes(viewId);
        	ComponentData data = EditorView.getComponentData(viewNodes);
        	
        	Gson gson = new Gson();
        	Map<String, Object> infoMap = new HashMap<String, Object>();
        	infoMap.put("viewName", dView.getViewName());
        	infoMap.put("viewCreator", dView.getViewCreator());
        	infoMap.put("viewRemark", dView.getViewRemark());
        	infoMap.put("viewVersion", dView.getViewVersion());
        	infoMap.put("updateTime", DateUtil.format(dView.getUpdateTime(), DateUtil.LV_FULL));
        	List<String> dirPaths = editorService.findPathDirNames(dView.getViewDir());
        	StringBuilder viewPath = new StringBuilder();
        	for (String dir : dirPaths) {
        		viewPath.append('/').append(dir);
        	}
        	infoMap.put("viewPath", viewPath.toString());
        	String viewInfo = gson.toJson(infoMap);
        	
        	String dataContent = gson.toJson(data);
        	
            response.setContentType("application/x-msdownload;");  
            response.setHeader("Content-disposition", "attachment; filename=view_" + java.net.URLEncoder.encode(dView.getViewName(), "UTF-8") + ".zip");  
//            int zipSize = viewInfo.length() + dataContent.length();
//            response.setHeader("Content-Length", String.valueOf(zipSize));
            
            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
            output = new BufferedOutputStream(zos);
            outputZipEntry(zos, viewInfo, "info.json");
            
            outputZipEntry(zos, dataContent, "data.json");
            
//            byte[] buff = new byte[10240];
//            bos.write(new String("测试").getBytes());
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (output != null) {
            	output.close();  
            }
        }  
		return null;
	}
	
	private void outputZipEntry(ZipOutputStream zos, String content, String entryName) throws Exception {
		if (Utils.isEmpty(content)) {
			// 为了防止文件为空
			content = "{}";
		} else {
			// 需要将json数据格式化
			content =J.formatJson(content);
		}
		ZipEntry entryInfo = new ZipEntry(entryName);
        zos.putNextEntry(entryInfo);
        byte[] b = content.getBytes();
    	zos.write(b, 0, b.length);
        zos.flush();
	}
	
	@RequestMapping(value="/toImport")
	@ResponseBody
	public Object toImport(HttpServletRequest request) throws Exception {
		String viewId = request.getParameter("viewId");
		View view = EditorView.buildToImportView(viewId);
		DialogCommand dialog = new DialogCommand("", "std", "导入",  DialogCommand.WIDTH_SMALL, DialogCommand.HEIGHT_SMALL, DialogCommand.POSITION_MIDDLE, "");
		dialog.setNode(view);
		return dialog;
	}
	
	@RequestMapping(value="/importView")
	@ResponseBody
	public Object importView(HttpServletRequest request) throws Exception {
		// 包含路径完整的文件名
		ZipInputStream zis = null;
		String viewId = request.getParameter("viewId");
		try {
			String uploadFile = request.getParameter("uploadFile");
			// 单个文件可以直接获取,多个文件用getFiles
			File file = fileService.getFile(uploadFile);
			
			zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
			ZipEntry entry = null;
			int batchSize = 10240;
			byte[] b = new byte[batchSize];
			Gson gson = new Gson();
			while((entry = zis.getNextEntry()) != null) {
				if (!entry.isDirectory()) {
					int r = -1;
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					while ((r = zis.read(b, 0, batchSize)) != -1) {
						baos.write(b, 0, r);
					}
					String content = baos.toString();
					String json = content.replace("\r", "").replace("\n", "").replace("\t", "");
					if ("info.json".equals(entry.getName())) {
						// FIXME 待补充
					} else if ("data.json".equals(entry.getName())){
						ComponentData data = gson.fromJson(json, ComponentData.class);
						editorService.rebuild(viewId, data);
					}
				}
			}
			zis.closeEntry();
        } catch (Exception e) {
	        e.printStackTrace();
        } finally {
        	if (zis != null) {
        		zis.close();
        	}
        }
		return new JSCommand("var d=$.dialog(this);editor.file.reloadEditor(d.ownerView,'" + viewId + "');d.close();");
	}
	
	@RequestMapping(value="/prepareSaveVersion/{viewId}")
	@ResponseBody
	public Object prepareSaveVersion(@PathVariable String viewId) throws Exception {
		DfishView dView = editorService.getView(viewId);
		View view = EditorView.editCreatorPanel(dView);
		return view;
		
	}
	
	@RequestMapping(value="/saveVersion")
	@ResponseBody
	public Object saveVersion(HttpServletRequest request) throws Exception {
		
		String viewId =request.getParameter("viewId");
		String viewCreator = request.getParameter("viewCreator");
		String viewRemark = Utils.getParameter(request, "viewRemark");
		
		CommandGroup cg = new CommandGroup();
		if(editorService.saveVersion(viewId,viewCreator,viewRemark)){
//			return new JSCommand("var d=$.dialog(this);$.alert('保存成功!');editor.file.reloadEditor(d.ownerView,'" + viewId + "');d.close();");
			cg.add(PubView.getAlertInfo("保存成功!"));
			cg.add(new JSCommand("var d=$.dialog(this);editor.file.reloadEditor(d.ownerView,'" + viewId + "');d.close();"));
		}else{
//			return new JSCommand("$.alert('与上一版本重复,保存失败!');$.dialog(this).close();");
			cg.add(new JSCommand("$.alert('与上一版本重复,保存失败!');$.dialog(this).close();"));
		}
		return cg;
	}
	
	@RequestMapping(value="/recoveryVersion")
	@ResponseBody
	public Object recoveryVersion(HttpServletRequest request) throws Exception {
		String viewId = request.getParameter("viewId");
		editorService.recoveryVersion(viewId);
		return new JSCommand("editor.file.reloadEditor(this,'" + viewId + "');");
	}
}
